package com.zhouheng.springbootmultithreading.module.producerconsumerissues.service.impl;

import com.zhouheng.springbootmultithreading.module.producerconsumerissues.service.Storage;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 仓库
 *
 * @author 周恒
 * @date 20190108 11:10:32
 * @since v1.0
 */
public class LockAwaitSignalStorageImpl implements Storage {

    /**
     * MAX_SIZE 仓库最大存储量
     */
    private int MAX_SIZE;

    public LockAwaitSignalStorageImpl(int MAX_SIZE) {
        this.MAX_SIZE = MAX_SIZE;
    }

    /**
     * list 仓库存储的载体
     */
    private LinkedList<Object> list = new LinkedList<>();

    /**
     * lock 锁 这样默认是对象锁，如果加static关键字就是类锁，Condition也要加static
     */
    private final Lock lock = new ReentrantLock();

    /**
     * full 仓库满的条件变量，给线程分队列
     */
    private final Condition full = lock.newCondition();

    /**
     * empty 仓库空的条件变量，给线程分队列
     */
    private final Condition empty = lock.newCondition();

    /**
     * 生产产品
     *
     * @param producer 描述此参数
     * @author 周恒
     * @date 20190108 11:10:33
     * @since v1.0
     */
    @Override
    public void produce(String producer) {
        lock.lock();
        try {
            // 如果仓库已满
            while (list.size() == MAX_SIZE) {
                System.out.println("仓库已满，【" + producer + "】： 暂时不能执行生产任务!");
                try {
                    // 由于条件不满足，生产阻塞
                    full.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 生产产品
            list.add(new Object());
            System.out.println("【" + producer + "】：生产了一个产品\t【现仓储量为】:" + list.size());
            empty.signalAll();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    /**
     * 消费产品
     *
     * @param consumer 描述此参数
     * @author 周恒
     * @date 20190108 11:10:33
     * @since v1.0
     */
    @Override
    public void consume(String consumer) {
        // 获得锁
        lock.lock();
        try {
            // 如果仓库存储量不足
            while (list.size() == 0) {
                System.out.println("仓库已空，【" + consumer + "】： 暂时不能执行消费任务!");
                try {
                    // 由于条件不满足，消费阻塞
                    empty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.remove();
            System.out.println("【" + consumer + "】：消费了一个产品\t【现仓储量为】:" + list.size());
            full.signalAll();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

}
